use chrono::{prelude::*, Duration};
use jsonwebtoken::{encode, decode,  Header, Algorithm, Validation, EncodingKey, DecodingKey, errors::ErrorKind};
use axum::Json;
use serde::{Serialize, Deserialize};
use serde_json::{ json, Value };

use crate::{code, uuid, query};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Claims {
    exp: i64,
    pub id: i32,
    pub cid: Option<u32>,
    pub role: Option<i8>,
    pub roles: Option<Vec<i32>>,
    pub name: Option<String>,
    pub username: String,
    pub uuid: String,
    
}
pub fn token_encode(id:i32, cid:Option<u32>, role:Option<i8>, roles: Option<Vec<i32>>, name:Option<String>, username:String, uid:Option<String>) -> Result<String, Json<Value>>{
    let now: DateTime<Local> = Local::now();
    let exp: DateTime<Local> = now + Duration::minutes(30);
    let exp: i64 = exp.timestamp();
    let auto_uuid = if uid.is_none() { uuid::create() } else { uid.unwrap() };
    if username.is_empty(){
        return Err(code::err_("加密数据不存在"));
    }
    let claims:Claims = Claims{
        exp: exp,
        id: id,
        cid: cid,
        role: role,
        roles: roles,
        name: name,
        username: username,
        uuid: auto_uuid,
    };
    let header: Header = Header::new(Algorithm::HS256);
    match encode(
        &header,
        &claims,
        &EncodingKey::from_secret("secret".as_ref())
    ){
        Ok(t) => Ok(String::from("Bearer ") + &t),
        Err(_) => Err(code::err_("token 加密失败"))
    }
}

pub fn token_decode(token:Option<&str>, exp:bool) -> Result<Claims, Json<Value>>{
    if token.is_none() {
        return Err(code::err_("token 不存在"));
    }
    let mut validation: Validation = Validation::new(Algorithm::HS256);
    validation.validate_exp = exp;
    validation.leeway = 0;
    let mut token = token.unwrap().split_whitespace();

    match token.nth(1) {
        Some(token) =>{
            // validation.insecure_disable_signature_validation();
            match decode::<Claims>(
                token,                                            
                &DecodingKey::from_secret("secret".as_ref()),
                &validation
            ){
                Ok(f) => {
                    let claims = &mut json!(f.claims);
                    let claims:Claims = Claims { 
                        exp: query::i64(claims, "exp")?, 
                        id: query::i32(claims, "id")?, 
                        cid: query::u32_op(claims, "cid")?, 
                        role: query::i8_op(claims, "role")?,
                        roles: query::vec_i32_op(claims, "roles")?, 
                        name: query::str_op(claims, "name")?,
                        username: query::str(claims, "username")?,
                        uuid: query::str(claims, "uuid")?, 
                    };
                    Ok(claims)
                },
                Err(err) => {
                    match *err.kind() {
                        ErrorKind::InvalidAlgorithm => Err(code::sys_("token 无效算法")),
                        ErrorKind::InvalidSignature => Err(code::sys_("token 无效签名")),
                        ErrorKind::InvalidAudience=> Err(code::err_code_msg_(201,"token 无效听众")),
                        ErrorKind::InvalidIssuer => Err(code::err_code_msg_(201,"token 无效签发者")),
                        ErrorKind::InvalidSubject => Err(code::err_code_msg_(201,"token 无效用户")),
                        ErrorKind::InvalidToken => Err(code::err_code_msg_(201,"无效 token")),
                        ErrorKind::ExpiredSignature => Err(code::err_code_msg_(202,"token 过期")),
                        ErrorKind::InvalidKeyFormat => Err(code::err_("token 密钥格式无效")),
                        _ => Err(code::err_("token 解密失败"))
                    }
                }
            }
        },
        None => Err(code::err_("token 不存在"))
    }
}